home *** CD-ROM | disk | FTP | other *** search
/ Games of Daze / Infomagic - Games of Daze (Summer 1995) (Disc 1 of 2).iso / x2ftp / msdos / misc / moonbas2 / moon.cpp < prev    next >
C/C++ Source or Header  |  1995-04-11  |  25KB  |  871 lines

  1. #include <stdlib.h>
  2. #include <stdio.h>
  3. #include <conio.h>
  4. #include <ctype.h>
  5. #include <time.h>
  6. #include <dos.h>
  7. #include <mem.h>
  8.  
  9. #include "random.h"
  10. #include "boolean.h"
  11. #include "fixed.h"
  12. #include "vga.h"
  13. #include "mouse.h"
  14. #include "world.h"
  15.  
  16. //#define DEBUG
  17.  
  18. #ifdef DEBUG
  19.  
  20.    static void     _Assert
  21.    (
  22.       const char * file,
  23.       unsigned     line,
  24.       const char * assertion
  25.    )
  26.    {
  27.       vga.end ();
  28.       fflush (stdout);
  29.       fprintf ( stderr, "\nAssertion failed (%s, line %u): %s\n",
  30.                 file, line, assertion );
  31.       fflush (stderr);
  32.       abort ();
  33.    }
  34.  
  35.    #define ASSERT(f) if (f) {} else _Assert ( __FILE__, __LINE__, #f )
  36.  
  37. #else
  38.  
  39.    #define ASSERT(f)
  40.  
  41. #endif
  42.  
  43. //----------------------------------------------------------------------------
  44.  
  45. const              view_size     = 64;
  46. const              view_start    = view_size / 2;
  47.  
  48. const              win_cen_x     = 160;
  49. const              win_cen_y     = 100;
  50.  
  51. const              black         = 0;
  52. const              cursor_color  = 255;
  53.  
  54. enum               key_t
  55. {
  56.    esc_key      = 27,
  57.    home_key     = 71,
  58.    up_arrow_key = 72,
  59.    pgup_key     = 73,
  60.    lt_arrow_key = 75,
  61.    center_key   = 76,
  62.    rt_arrow_key = 77,
  63.    end_key      = 79,
  64.    dn_arrow_key = 80,
  65.    pgdn_key     = 81
  66. };
  67.  
  68. //----------------------------------------------------------------------------
  69. // The viewer's position variables.
  70. //----------------------------------------------------------------------------
  71.  
  72. struct             viewer_t
  73. {
  74.    int             x;
  75.    int             y;
  76.    int             z;
  77.  
  78.    angle_t         angle;
  79.    fixed           sine;
  80.    fixed           cosine;
  81. };
  82.  
  83. static viewer_t    viewer;
  84.  
  85. //----------------------------------------------------------------------------
  86. // The view window.
  87. //----------------------------------------------------------------------------
  88.  
  89. static win_t       win =
  90. {
  91.    0, 0, 320, 200
  92. };
  93.  
  94. //----------------------------------------------------------------------------
  95. // The column data structures used by draw_row.
  96. //----------------------------------------------------------------------------
  97.  
  98. struct             col_t
  99. {
  100.    int             y;
  101.    unsigned char   color;
  102. };
  103.  
  104. static col_t       col     [ 321 ];
  105. static col_t       old_col [ 321 ];
  106.  
  107. //----------------------------------------------------------------------------
  108. // FUNCTION  mul_and_div
  109. //----------------------------------------------------------------------------
  110. // This calculates (a * b) / c with increased precision by using all 64 bits
  111. // from the multiplication in calculating the result of the division.
  112. //----------------------------------------------------------------------------
  113.  
  114. int                mul_and_div ( int a, int b, int c );
  115.  
  116. #pragma aux mul_and_div =  \
  117.    "imul ebx"              \
  118.    "idiv ecx"              \
  119.    parm caller [eax] [ebx] [ecx] \
  120.    value [eax]             \
  121.    modify [eax ebx ecx edx];
  122.  
  123. //----------------------------------------------------------------------------
  124. // FUNCTION  dot_product
  125. //----------------------------------------------------------------------------
  126. //
  127. // dot_product = (u1 * v1 + u2 * v2) / 2^16;
  128. //
  129. // This is designed to be used with integer sine and cosine values in the
  130. // range -2^16..2^16; hence the division by 2^16 following the dot product.
  131. // Using this function improves precision since it has a 64-bit addition.
  132. //
  133. //----------------------------------------------------------------------------
  134.  
  135. int                dot_product ( int u1, int u2, int v1, int v2 );
  136.  
  137. #pragma aux dot_product =  \
  138.    "imul edx"              \
  139.    "mov esi, edx"          \
  140.    "mov edi, eax"          \
  141.    "mov eax, ebx"          \
  142.    "imul ecx"              \
  143.    "add eax, edi"          \
  144.    "adc edx, esi"          \
  145.    "shrd eax, edx, 16"     \
  146.    parm caller [eax] [ebx] [edx] [ecx] \
  147.    value [eax]             \
  148.    modify [eax ebx ecx edx esi edi];
  149.  
  150. //----------------------------------------------------------------------------
  151. // FUNCTION  view_overhead_map
  152. //----------------------------------------------------------------------------
  153.  
  154. static void        view_overhead_map
  155. (
  156.    void
  157. )
  158. {
  159.    int start_x  =  (int) (viewer.x / scale_area) - win_cen_x;
  160.    int start_y  =  (int) (viewer.y / scale_area) - win_cen_y;
  161.  
  162.    start_x &= clip_mask_x;
  163.    start_y &= clip_mask_y;
  164.  
  165.    // Draw the map, with the viewer's position in the center.
  166.  
  167.    const           sequ_addr     = 0x3C4;
  168.    const           bytes_per_row = 80;
  169.    extern char *   a_page;
  170.  
  171.    for ( int plane = 0; plane < 4; ++ plane )
  172.    {
  173.       outpw ( sequ_addr, 0x02 | (0x100 << plane) );
  174.  
  175.       int map_x = start_x;
  176.  
  177.       for ( int x = 0; x < bytes_per_row; ++ x )
  178.       {
  179.          int map_y = start_y;
  180.  
  181.          char * pixel_p = a_page + x;
  182.          char * stop_p  = pixel_p + bytes_per_row * 200;
  183.  
  184.          for ( ; pixel_p < stop_p; pixel_p += bytes_per_row )
  185.          {
  186.             *pixel_p = color_map [map_x][map_y];
  187.             map_y    = (map_y + 1) & clip_mask_y;
  188.          }
  189.          map_x = (map_x + 4) & clip_mask_x;
  190.       }
  191.       start_x = (start_x + 1) & clip_mask_x;
  192.    }
  193.  
  194.    // Draw a line indicating the viewer's heading.
  195.  
  196.    int x1 = dot_product (  viewer.sine,   viewer.cosine,  20, 0 ) + 160;
  197.    int y1 = dot_product ( -viewer.cosine, viewer.sine,    20, 0 ) + 100;
  198.    int x2 = dot_product (  viewer.sine,   viewer.cosine,  30, 0 ) + 160;
  199.    int y2 = dot_product ( -viewer.cosine, viewer.sine,    30, 0 ) + 100;
  200.  
  201.    win.line ( x1, y1, x2, y2, cursor_color );
  202.  
  203.    // Draw a marker at the center indicating the viewer's position.
  204.  
  205.    win.rect ( 159, 99, 162, 102, black );
  206.    win.point ( 160, 100, cursor_color );
  207. }
  208.  
  209. //----------------------------------------------------------------------------
  210. //
  211. // The graphics workhorse routines.
  212. //
  213. //----------------------------------------------------------------------------
  214.  
  215. //----------------------------------------------------------------------------
  216. // FUNCTION  calc_color
  217. //----------------------------------------------------------------------------
  218.  
  219. inline unsigned char calc_color
  220. (
  221.    int             map_x,
  222.    int             map_y
  223. )
  224. {
  225.    return  color_map [map_x][map_y];
  226. }
  227.  
  228. //----------------------------------------------------------------------------
  229. // FUNCTION  draw_row
  230. //----------------------------------------------------------------------------
  231.  
  232. static void        draw_row
  233. (
  234.    void
  235. )
  236. {
  237.    const           sequ_addr     = 0x3C4;
  238.    const           bytes_per_row = 80;
  239.    extern char *   a_page;
  240.  
  241.    int             x;
  242.  
  243.    for ( x = 0; x < 320; ++ x )
  244.    {
  245.       if      ( col [x].y < 0   ) col [x].y = 0;
  246.       else if ( col [x].y > 200 ) col [x].y = 200;
  247.    }
  248.  
  249.    for ( int plane = 0; plane < 4; ++ plane )
  250.    {
  251.       outpw ( sequ_addr, 0x02 | (0x100 << plane) );
  252.  
  253.       int col_x = plane;
  254.  
  255.       for ( x = 0; x < bytes_per_row; ++ x )
  256.       {
  257.          ASSERT ( old_col [col_x].y >= 0   );
  258.          ASSERT ( old_col [col_x].y <= 200 );
  259.          ASSERT ( col     [col_x].y >= 0   );
  260.          ASSERT ( col     [col_x].y <= 200 );
  261.  
  262.          char * pixel_p = & a_page [bytes_per_row*old_col [col_x].y + x];
  263.          char * stop_p  = & a_page [bytes_per_row*    col [col_x].y + x];
  264.  
  265.          int color = old_col [col_x].color;
  266.  
  267.          int den   = col [col_x].y - old_col [col_x].y;
  268.          int num   = col [col_x].color - color;
  269.  
  270.          int color_inc;
  271.  
  272.          if ( num < 0 ) { color_inc = -1; num = -num; }
  273.          else             color_inc = 1;
  274.  
  275.          int err = 0;
  276.  
  277.          while ( pixel_p < stop_p )
  278.          {
  279.             *pixel_p  = (unsigned char) color;
  280.             pixel_p  += bytes_per_row;
  281.  
  282.             err += num;
  283.             while ( err >= den )
  284.             {
  285.                err   -= den;
  286.                color += color_inc;
  287.             }
  288.          }
  289.  
  290.          old_col [col_x].y     = col [col_x].y;
  291.          old_col [col_x].color = col [col_x].color;
  292.  
  293.          col_x += 4;
  294.       }
  295.    }
  296. }
  297.  
  298. //----------------------------------------------------------------------------
  299. // FUNCTION  rotate
  300. //----------------------------------------------------------------------------
  301. // Takes an (x, y) coordinate pair and rotates it using the variables
  302. // sine and cosine, which are 32-bit integer values ranging from -65536 to
  303. // 65536.
  304. //----------------------------------------------------------------------------
  305.  
  306. inline void        rotate
  307. (
  308.    int &           x,
  309.    int &           y,
  310.    int             sine,
  311.    int             cosine
  312. )
  313. {
  314.    int temp_x = x;
  315.    int temp_y = y;
  316.  
  317.    x = dot_product ( cosine, -sine, temp_x, temp_y );
  318.    y = dot_product ( sine, cosine,  temp_x, temp_y );
  319. }
  320.  
  321. //----------------------------------------------------------------------------
  322. // FUNCTION  view_3d
  323. //----------------------------------------------------------------------------
  324.  
  325. static void        view_3d
  326. (
  327.    void
  328. )
  329. {
  330.    const sz = 240; // Dist. from viewer's eye to screen in pixels
  331.  
  332.    // Map coordinate system setup:
  333.  
  334.    int viewer_map_x = viewer.x / scale_area;
  335.    int viewer_map_y = viewer.y / scale_area;
  336.  
  337.    int map_start_x,     map_start_y;
  338.    int map_start_x_inc, map_start_y_inc;
  339.    int map_x_inc,       map_y_inc;
  340.  
  341.    int start_x,         start_y;
  342.  
  343.    if ( viewer.angle < 450 || viewer.angle >= 3150 )
  344.    {
  345.       map_start_x     = (viewer_map_x - view_start) & clip_mask_x;
  346.       map_start_y     = (viewer_map_y - view_start) & clip_mask_y;
  347.       map_start_x_inc = 0;
  348.       map_start_y_inc = 1;
  349.       map_x_inc       = 1;
  350.       map_y_inc       = 0;
  351.  
  352.       start_x         = -view_start * scale_area;
  353.       start_y         =  view_start * scale_area;
  354.    }
  355.    else if ( viewer.angle < 1350 )
  356.    {
  357.       map_start_x     = (viewer_map_x + view_start) & clip_mask_x;
  358.       map_start_y     = (viewer_map_y - view_start) & clip_mask_y;
  359.       map_start_x_inc = -1;
  360.       map_start_y_inc = 0;
  361.       map_x_inc       = 0;
  362.       map_y_inc       = 1;
  363.  
  364.       start_x         = view_start * scale_area;
  365.       start_y         = view_start * scale_area;
  366.    }
  367.    else if ( viewer.angle < 2250 )
  368.    {
  369.       map_start_x     = (viewer_map_x + view_start) & clip_mask_x;
  370.       map_start_y     = (viewer_map_y + view_start) & clip_mask_y;
  371.       map_start_x_inc = 0;
  372.       map_start_y_inc = -1;
  373.       map_x_inc       = -1;
  374.       map_y_inc       = 0;
  375.  
  376.       start_x         =  view_start * scale_area;
  377.       start_y         = -view_start * scale_area;
  378.    }
  379.    else
  380.    {
  381.       map_start_x     = (viewer_map_x - view_start) & clip_mask_x;
  382.       map_start_y     = (viewer_map_y + view_start) & clip_mask_y;
  383.       map_start_x_inc = 1;
  384.       map_start_y_inc = 0;
  385.       map_x_inc       = 0;
  386.       map_y_inc       = -1;
  387.  
  388.       start_x         = -view_start * scale_area;
  389.       start_y         = -view_start * scale_area;
  390.    }
  391.  
  392.    // World coordinate system setup:
  393.  
  394.    start_x -= (viewer.x % scale_area);
  395.    start_y += (viewer.y % scale_area);
  396.  
  397.    int world_x_inc =  map_x_inc * scale_area;
  398.    int world_y_inc = -map_y_inc * scale_area;
  399.  
  400.    rotate ( start_x,     start_y,     viewer.sine, viewer.cosine );
  401.    rotate ( world_x_inc, world_y_inc, viewer.sine, viewer.cosine );
  402.  
  403.    int start_x_inc  =  world_y_inc;
  404.    int start_y_inc  = -world_x_inc;
  405.  
  406.    // Draw rows:
  407.  
  408.    vga.clear ( 0 );
  409.  
  410.    for ( int x = 0; x < 320; ++ x )
  411.    {
  412.       old_col [x].y     = 200;
  413.       old_col [x].color = 0;
  414.       col [x].y         = 200;
  415.       col [x].color     = 0;
  416.    }
  417.  
  418.    for ( int nr_rows = view_size / 2; nr_rows > 0; -- nr_rows )
  419.    {
  420.       int map_x   = map_start_x;
  421.       int map_y   = map_start_y;
  422.  
  423.       int world_x = start_x;
  424.       int world_y = start_y;
  425.       int world_z = viewer.z - alt_map [map_x][map_y] * scale_height;
  426.  
  427.       int last_sx    = 320;
  428.       int last_sy    = 0;
  429.       int last_color = 0;
  430.  
  431.       int nr_cols = view_size;
  432.  
  433.       while ( nr_cols > 0 )
  434.       {
  435.          // Calculate the screen coordinates.
  436.  
  437.          if ( world_y > 0 )
  438.          {
  439.             int sx = mul_and_div ( world_x, sz, world_y ) + win_cen_x;
  440.             int sy = mul_and_div ( world_z, sz, world_y ) + win_cen_y;
  441.             int color;
  442.  
  443.             color = calc_color ( map_x, map_y );
  444.  
  445.             // Draw if the point is onscreen.
  446.  
  447.             if ( sx > win.x1 )
  448.             {
  449.                int den   = sx - last_sx;
  450.  
  451.                int num   = color - last_color;
  452.                int color_inc;
  453.                if ( num < 0 ) { color_inc = -1; num = -num; }
  454.                else             color_inc = 1;
  455.                int err = 0;
  456.  
  457.                int num2 = sy - last_sy;
  458.                int last_sy_inc;
  459.                if ( num2 < 0 ) { last_sy_inc = -1; num2 = -num2; }
  460.                else              last_sy_inc = 1;
  461.                int err2 = 0;
  462.  
  463.                // Left edge clipping:
  464.  
  465.                if ( last_sx < win.x1 )
  466.                {
  467.                   int delta = win.x1 - last_sx;
  468.  
  469.                   err = num * delta % den;
  470.                   last_color += color_inc * num * delta / den;
  471.  
  472.                   err2 = num2 * delta % den;
  473.                   last_sy += last_sy_inc * num2 * delta / den;
  474.  
  475.                   last_sx = win.x1;
  476.                }
  477.  
  478.                // Right edge clipping:
  479.  
  480.                if ( sx > win.x2 )
  481.                   sx = win.x2;
  482.  
  483.                // Draw the section:
  484.  
  485.                for ( int x = last_sx; x < sx; ++ x )
  486.                {
  487.                   ASSERT ( x >= 0 && x < 320 );
  488.  
  489.                   col [x].y     = last_sy;
  490.                   col [x].color = (unsigned char) last_color;
  491.  
  492.                   err += num;
  493.                   while ( err >= den )
  494.                   {
  495.                      err -= den;
  496.                      last_color += color_inc;
  497.                   }
  498.  
  499.                   err2 += num2;
  500.                   while ( err2 >= den )
  501.                   {
  502.                      err2 -= den;
  503.                      last_sy += last_sy_inc;
  504.                   }
  505.                }
  506.  
  507.                if ( sx == win.x2 )
  508.                   break;
  509.             }
  510.  
  511.             last_sx    = sx;
  512.             last_sy    = sy;
  513.             last_color = color;
  514.          }
  515.  
  516.          // Go to the next point.
  517.  
  518.          map_x = (map_x + map_x_inc) & clip_mask_x;
  519.          map_y = (map_y + map_y_inc) & clip_mask_y;
  520.  
  521.          world_x += world_x_inc;
  522.          world_y += world_y_inc;
  523.          world_z  = viewer.z - alt_map [map_x][map_y] * scale_height;
  524.  
  525.          -- nr_cols;
  526.       }
  527.  
  528.       // Draw this row of points.
  529.  
  530.       draw_row ();
  531.  
  532.       // Move the starting position to the next row.
  533.  
  534.       start_x += start_x_inc;
  535.       start_y += start_y_inc;
  536.  
  537.       map_start_x = (map_start_x + map_start_x_inc) & clip_mask_x;
  538.       map_start_y = (map_start_y + map_start_y_inc) & clip_mask_y;
  539.    }
  540.  
  541.    // Finish the drawing by drawing down to the bottom edge of the screen.
  542.  
  543.    for ( x = 0; x < 320; ++ x )
  544.    {
  545.       col [x].y     = win.y2;
  546.       col [x].color = calc_color (viewer_map_x, viewer_map_y);
  547.    }
  548.  
  549.    draw_row ();
  550. }
  551.  
  552. //----------------------------------------------------------------------------
  553. // FUNCTION  set_palette
  554. //----------------------------------------------------------------------------
  555.  
  556. struct             color_t
  557. {
  558.    char            r;
  559.    char            g;
  560.    char            b;
  561. };
  562.  
  563. static void        set_palette
  564. (
  565.    void
  566. )
  567. {
  568.    const DAC_write_index = 0x3C8;
  569.    const DAC_data_index  = 0x3C9;
  570.  
  571.    color_t         colors [ 256 ];
  572.    int             i;
  573.  
  574.    memset ( colors, 0, sizeof (colors) );
  575.  
  576.    for ( i = 0; i < 64; ++ i )
  577.    {
  578.       colors [i+1].r  = (unsigned char) i;
  579.       colors [i+1].g  = (unsigned char) (i * i / 63);
  580.       colors [i+1].b  = (unsigned char) (i * i / 63);
  581.    }
  582.  
  583.    colors [255].r  = 16;
  584.    colors [255].g  = 63;
  585.    colors [255].b  = 0;
  586.  
  587.    for ( i = 0; i < 256; ++ i )
  588.    {
  589.       outp ( DAC_write_index, i );
  590.       outp ( DAC_data_index, colors [i].r );
  591.       outp ( DAC_data_index, colors [i].g );
  592.       outp ( DAC_data_index, colors [i].b );
  593.    }
  594. }
  595.  
  596. //----------------------------------------------------------------------------
  597. // FUNCTION  interact
  598. //----------------------------------------------------------------------------
  599.  
  600. enum               view_t
  601. {
  602.    cockpit_view,
  603.    map_view
  604. };
  605.  
  606. static void        interact
  607. (
  608.    void
  609. )
  610. {
  611.    const           clearance     = 8           * scale_height;
  612.    const           max_altitude  = (max_alt+4) * scale_height;
  613.  
  614.    // Initialize the palette.
  615.  
  616.    set_palette ();
  617.  
  618.    // Store the mouse coordinates so we can tell later if it has moved.
  619.  
  620.    mouse.update ();
  621.    int old_mouse_x = mouse.x;
  622.    int old_mouse_y = mouse.y;
  623.  
  624.    // Initialize the player's position, heading and velocities.
  625.  
  626.    viewer.x     = 4 * scale_area;
  627.    viewer.y     = 4 * scale_area;
  628.    viewer.z     = color_map [4][4] * scale_height + clearance;
  629.    viewer.angle = 1800;
  630.  
  631.    int vel      = 0; // Forward velocity
  632.    int vz       = 0; // Vertical velocity
  633.    int va       = 0; // Angular velocity
  634.  
  635.    // Initialize other variables.
  636.  
  637.    view_t          view          = cockpit_view;
  638.  
  639.    boolean         showing_mouse = false;
  640.    boolean         buttons_used  = false;
  641.    boolean         done          = false;
  642.  
  643.    //-------------------------------------------------------------------------
  644.    // The main interaction loop:
  645.    //-------------------------------------------------------------------------
  646.  
  647.    while ( ! done )
  648.    {
  649.       //----------------------------------------------------------------------
  650.       // Update the player's state.
  651.       //----------------------------------------------------------------------
  652.  
  653.       // Heading
  654.  
  655.       viewer.angle += va;
  656.  
  657.       while ( viewer.angle <  0    )  viewer.angle += 3600;
  658.       while ( viewer.angle >= 3600 )  viewer.angle -= 3600;
  659.  
  660.       FIX_cos_sin ( viewer.angle, & viewer.cosine, & viewer.sine );
  661.  
  662.       // Position
  663.  
  664.       int vx = mul_and_div ( vel, -viewer.sine,  65536 );
  665.       int vy = mul_and_div ( vel, viewer.cosine, 65536 );
  666.  
  667.       int map_x = (int) (viewer.x / scale_area);
  668.       int map_y = (int) (viewer.y / scale_area);
  669.  
  670.       viewer.x += vx;
  671.       viewer.y += vy;
  672.  
  673.       while ( viewer.x <  0            )  viewer.x += world_size_x;
  674.       while ( viewer.x >= world_size_x )  viewer.x -= world_size_x;
  675.  
  676.       while ( viewer.y <  0            )  viewer.y += world_size_y;
  677.       while ( viewer.y >= world_size_y )  viewer.y -= world_size_y;
  678.  
  679.       // Elevation
  680.  
  681.       viewer.z += vz;
  682.  
  683.       if ( viewer.z < alt_map [map_x][map_y] * scale_height + clearance )
  684.       {
  685.          viewer.z = alt_map [map_x][map_y] * scale_height + clearance;
  686.          vz       = 0;
  687.       }
  688.       else if ( viewer.z > max_altitude )
  689.       {
  690.          viewer.z = max_altitude;
  691.          vz       = 0;
  692.       }
  693.  
  694.       //----------------------------------------------------------------------
  695.       // Draw the view.
  696.       //----------------------------------------------------------------------
  697.  
  698.       if ( view == cockpit_view )  view_3d ();
  699.       else                         view_overhead_map ();
  700.  
  701.       if ( showing_mouse )
  702.       {
  703.          win.rect ( 0,         mouse.y-2, 3,         mouse.y+3, black       );
  704.          win.rect ( 0,         mouse.y-1, 2,         mouse.y+2, cursor_color);
  705.          win.rect ( 317,       mouse.y-2, 320,       mouse.y+3, black       );
  706.          win.rect ( 318,       mouse.y-1, 320,       mouse.y+2, cursor_color);
  707.          win.rect ( mouse.x-2, 0,         mouse.x+3, 3,         black       );
  708.          win.rect ( mouse.x-1, 0,         mouse.x+2, 2,         cursor_color);
  709.       }
  710.  
  711.       vga.update ();
  712.  
  713.       //----------------------------------------------------------------------
  714.       // Handle keyboard input.
  715.       //----------------------------------------------------------------------
  716.  
  717.       while ( kbhit () )
  718.       {
  719.          int key = tolower (getch ());
  720.  
  721.          if ( key == 0 )
  722.          {
  723.             key = getch ();
  724.  
  725.             switch ( key )
  726.             {
  727.             case up_arrow_key : vz  += scale_height / 2; break;
  728.             case dn_arrow_key : vz  -= scale_height / 2; break;
  729.             case lt_arrow_key : va  -= 5; break;
  730.             case rt_arrow_key : va  += 5; break;
  731.             case center_key   : vel  = 0; va = 0; vz = 0; break;
  732.             default: break;
  733.             }
  734.          }
  735.          else switch ( key )
  736.          {
  737.          case esc_key: // Drop through
  738.          case 'q': done = true; break;
  739.          case 'm':
  740.             view = (view == cockpit_view) ? map_view : cockpit_view;
  741.             break;
  742.          case 'n': viewer.angle = 0;    break;
  743.          case 'e': viewer.angle = 900;  break;
  744.          case 's': viewer.angle = 1800; break;
  745.          case 'w': viewer.angle = 2700; break;
  746.          case 'r': viewer.angle = (viewer.angle + 1800) % 3600; break;
  747.          case '+': // Drop through
  748.          case '=': vel -= scale_area / 8; break;
  749.          case '-': vel += scale_area / 8; break;
  750.          default: break;
  751.          }
  752.  
  753.          showing_mouse = false;
  754.       }
  755.  
  756.       //----------------------------------------------------------------------
  757.       // Handle mouse input.
  758.       //----------------------------------------------------------------------
  759.  
  760.       if ( mouse.exists )
  761.       {
  762.          mouse.update ();
  763.  
  764.          if ( mouse.x != old_mouse_x || mouse.y != old_mouse_y )
  765.          {
  766.             showing_mouse = true;
  767.  
  768.             old_mouse_x = mouse.x;
  769.             old_mouse_y = mouse.y;
  770.  
  771.             va = mouse.x - 160;
  772.             vz = mouse.y - 100;
  773.  
  774.             // Give the mouse an exponential response curve.
  775.  
  776.             if (va < 0)  va = va * va / -160;
  777.             else         va = va * va / 160;
  778.  
  779.             if (vz < 0)  vz = vz * vz /  (scale_height / 16);
  780.             else         vz = vz * vz / -(scale_height / 16);
  781.          }
  782.  
  783.          if ( mouse.buttons ) // If any button is down
  784.          {
  785.             if ( ! buttons_used )
  786.             {
  787.                view = (view == cockpit_view) ? map_view : cockpit_view;
  788.  
  789.                buttons_used = true;
  790.             }
  791.          }
  792.          else
  793.          {
  794.             buttons_used = false;
  795.          }
  796.       }
  797.    }
  798. }
  799.  
  800. //----------------------------------------------------------------------------
  801. // FUNCTION  check_equipment
  802. //----------------------------------------------------------------------------
  803. // Check for a mouse.
  804. //----------------------------------------------------------------------------
  805.  
  806. static void check_equipment ( void )
  807. {
  808.    mouse.init ();
  809.  
  810.    if ( mouse.exists )
  811.    {
  812.       printf ( "Mouse detected.\n" );
  813.    }
  814.    else
  815.    {
  816.       printf ( "No mouse detected.\n" );
  817.    }
  818.  
  819.    if ( ! vga.exists () )
  820.    {
  821.       fprintf ( stderr, "This program requires a VGA graphics adaptor.\n" );
  822.       exit (1);
  823.    }
  824. }
  825.  
  826. //----------------------------------------------------------------------------
  827. // FUNCTION  main
  828. //----------------------------------------------------------------------------
  829. // Sets up and takes down the game environment.  Checks first to be sure
  830. // the necessary equipment is available, then changes screen modes before
  831. // passing control to the interactive game-playing module.  Upon regaining
  832. // control, main resets the screen to its previous state.
  833. //----------------------------------------------------------------------------
  834.  
  835. const char *       instructions =
  836.  
  837.    "\n\"Moonbase\" 3D Landscape Demo\n"
  838.    "────────────────────────────\n\n"
  839.    "Use the mouse or arrow keys to steer.  Other keys are:\n\n"
  840.    "  + -  Increase/Decrease forward velocity\n"
  841.    "  m    Toggle satellite view\n"
  842.    "  Esc  Quit\n"
  843.    "\nPress Enter to begin.\n"
  844.    "";
  845.  
  846. const char *       closing_msg =
  847.  
  848.    "Moonbase was written by James McNeill (mcneja@wwc.edu)\n"
  849.    "using Watcom C++ and the PMODE/W DOS extender.\n";
  850.  
  851. int                main
  852. (
  853.    void
  854. )
  855. {
  856.    check_equipment ();
  857.  
  858.    WORLD_generate ();
  859.  
  860.    printf ( instructions );
  861.    if ( getch () == 0 ) getch ();
  862.  
  863.    vga.start ();
  864.    interact  ();
  865.    vga.end   ();
  866.  
  867.    printf ( closing_msg );
  868.  
  869.    return 0;
  870. }
  871.